/**
 * @file swei_alarm.c
 * @brief 
 * @author  ()
 * @version 1.0
 * @date 2024-09-13
 * 
 * @copyright Copyright (C) 2019 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2024-09-13 <td>1.0     <td>     <td>内容
 * </table>
 */
#include "include/port/swei_log.h"
#include "include/swei_common.h"
#include "include/swei_alarm.h"
#include "include/port/swei_wrapper.h"
#include "service/include/swei_package.h"



swei_alarm_t alarm_table[ALARM_MAX] = {
    0
};


const char *swei_alarm_id_str[ALARM_MAX] = {
	"NULL",
	"Vibration",
	"Power Off",
	"Tilt",
	"Overturn",
	"Damage",
	"GEO Fence",
	"Dev Fault",
	"Vehicle Fault",
	"Unusual Move",
};
#define ALARM_MAX_SIZE (128)
QueueHandle_t alarm_queue = NULL;

/**
 * @brief 初始化告警功能
 */
void    swei_alarm_init(void)
{
    if (!alarm_queue)
    {
        alarm_queue = xQueueCreate(ALARM_MAX_SIZE, sizeof(swei_alarmtype_t));
        if (NULL == alarm_queue)
        {
            log_e("create queue for alarm failed!\r\n");
            return;
        }
    }

    if (NULL == alarm_queue)
    {
        log_e("create queue for alarm failed!\r\n");
        return;
    }
}

/**
 * @brief 告警功能去初始化，unused api
 */
void    swei_alarm_deinit(void)
{

}

/**
 * @brief 获取队列状态
 * @return uint32_t 
 */
uint32_t swei_alarm_queue_size(void)
{
    if(NULL == alarm_queue) {
        return 0;
    }

    return uxQueueMessagesWaiting(alarm_queue);
}

bool swei_alarm_queue_is_empty(void)
{
    if(NULL == alarm_queue) {
        return true;
    }

    return (uxQueueMessagesWaiting(alarm_queue) == pdFAIL);
}

void swei_alarm_id_clear(swei_alarm_id_e alarm_id)
{
    
    if(alarm_id >= ALARM_MAX)
        return;

    taskENTER_CRITICAL();
    alarm_table[alarm_id].status = false;
    memset(&alarm_table[alarm_id].timer, 0, sizeof(utils_time_t));
    taskEXIT_CRITICAL();

    
}




#include "utils/utils_timer.h"
/// @brief 设置告警标志， 所有告警通过这个接口完成入队和判断，然后由server process 进行管理
/// @param alarm_id 
/// @return 
int32_t swei_alarm_setup(swei_alarm_id_e alarm_id)
{
    //swei_alarm_t *alarm;
    if(alarm_id >= ALARM_MAX)
        return -1;
    // add mutex lock up
    //taskENTER_CRITICAL();

    // alarm timer timeout 5min, recounter for next alarm;
    if( (true == alarm_table[alarm_id].status) && (utils_time_is_expired(&(alarm_table[alarm_id].timer))))
    {
        alarm_table[alarm_id].status = false;
        
    } else if (true == alarm_table[alarm_id].status) {
        
        log_e("swei alarm[%s] already got one in queue.");
        return -1;
    }

    // push in alarm lists
    if(false == alarm_table[alarm_id].status)
    {
        swei_alarmtype_t *node;

        node = swei_malloc(sizeof(swei_alarmtype_t));
        
        if (node == NULL) {
            
    		log_e("swei alarm[%s] init fail.\r\n", swei_alarm_id_str[alarm_id]);
            taskEXIT_CRITICAL();
    		return -1;
        
    	} else {
            
            memset(node, 0, sizeof(swei_alarmtype_t));
            node->id = alarm_id;
            node->ts = swei_getms();	
    	}

        swei_alarm_push(node);
		log_i("send swei alarm[%s].\r\n", swei_alarm_id_str[alarm_id]);

        // add timer to countdown 300s and clear alarm status
        utils_time_countdown_ms(&(alarm_table[alarm_id].timer), 5 * 60 * 1000);
        
        alarm_table[alarm_id].status = true;
    }

    // add mutex lock off
    //taskEXIT_CRITICAL();

    return 0;
}

/// @brief 内部接口，非外部调用，用于推送告警节点入队
/// @param alarm_id 
int32_t  swei_alarm_push(swei_alarmtype_t *pnode)
{
    if (!alarm_queue)
    {
        alarm_queue = xQueueCreate(ALARM_MAX_SIZE, sizeof(swei_alarmtype_t));
        if (NULL == alarm_queue)
        {
            log_e("create queue for alarm failed!\r\n");
            return -EIO;
        }
    }

    if (NULL == alarm_queue)
    {
        log_e("create queue for alarm failed!\r\n");
        return -EIO;
    }

    if(pdPASS == xQueueSendToBack(alarm_queue, pnode, 0))
    {
        return 0;
    }

    return -EIO;
}


/// @brief 
/// @param status 
/// @return 
int32_t swei_alarm_peek(swei_alarmtype_t *pnode)
{
    if(NULL == alarm_queue)
    {
        alarm_queue = xQueueCreate(ALARM_MAX_SIZE, sizeof(swei_datatype_t));
        if(NULL == alarm_queue)      
        {
            log_e("create queue for alarm failed!\r\n");
            return -EIO;
        }
    }

    if(NULL == alarm_queue)
        return -EIO;
    
    // @TODO: pnode增加有效性判断

    if(pdPASS == xQueuePeek(alarm_queue, pnode, 0))
    {
        return 0;
    }

    return -EIO;
}


/**
 * @brief 告警消息出队，如果传入node不为空，则需要peek是否第一条消息为目标消息，才能正常出队，为空则直接出队
 * @param  node    待校验的节点
 * @return int32_t 
 */
int32_t swei_alarm_pop(swei_alarmtype_t *node)
{
    swei_alarmtype_t temp;

    // 1. 优先判断队列创建情况
    if(NULL == alarm_queue)
    {
        alarm_queue = xQueueCreate(ALARM_MAX_SIZE, sizeof(swei_datatype_t));
        if(NULL == alarm_queue)
        {
            log_e("create queue for alarm failed!\r\n");
            return -EIO;
        }
    }

    // 2. 入参判断，如果为空，则默认推出队列第一个节点
    if(!node)
    {
        if(pdPASS == xQueueReceive(alarm_queue, &temp, 0))
        {
            swei_alarm_id_clear(temp.id);
            return SUCC;
        }
    }

    // 3. 告警匹配出队
    if(pdPASS == xQueuePeek(alarm_queue, &temp, 0))
    {
        // 3.1 节点id匹配
        if(temp.id != node->id) 
        {
            return SUCC;
        }

        // 3.2 节点出队
        if(pdPASS == xQueueReceive(alarm_queue, node, 0))
        {
            swei_alarm_id_clear(node->id);
            return SUCC;
        }
    }

    return -EIO;
}


